﻿using Microsoft.Xna.Framework;
using Blockey.GameplayScreens;
using Microsoft.Xna.Framework.Input;
using BlockeyEssentials.Input;
using BlockeyEssentials;
using Microsoft.Xna.Framework.Graphics;

namespace Blockey.GameObjects3D
{
    public class Goalie : Person3D
    {
        public Goalie(Game oGame, ControllingPlayer oPlayer, Alliance oTeamSide, Goal3D oGoal)
            : base(oGame, oPlayer, oTeamSide)
        {
            if (oTeamSide == Alliance.Home)
            {
                SetBounds(oGoal, false);
            }
            if (oTeamSide == Alliance.Away)
            {
                SetBounds(oGoal, true);
            }

            _HelmetDrawable.SetTransformation(null, _RotationCurrent, null);
            _HeadDrawable.SetTransformation(null, _RotationCurrent, null);
            _BodyDrawable.SetTransformation(null, _RotationCurrent, null);
            _EyesDrawable.SetTransformation(null, _RotationCurrent, null);

            var oCenter = m_oGoalieArea.Center;
            SetStartPosition(oCenter * new Vector3(1, 1, 0));

            Magnitude *= 1.5f;

            Friction *= 5f;
            m_fDefaultFriction = Friction;
        }

        private void SetBounds(Goal3D oGoal, bool oRight)
        {
            m_oGoalBounds = oGoal.CollisionArea;
            m_oDiveAreaBox = m_oGoalBounds;
            var oGoalLengthX = MathHelper.Distance(m_oDiveAreaBox.Max.X, m_oDiveAreaBox.Min.X);

            float fShift;

            fShift = (oGoalLengthX + 1);
            if (oRight)
                m_oDiveAreaBox.Max.X -= fShift;
            else
                m_oDiveAreaBox.Min.X += fShift;

            fShift = oGoalLengthX * 2.5f;
            if (oRight)
                m_oDiveAreaBox.Min.X -= fShift;
            else
                m_oDiveAreaBox.Max.X += fShift;

            fShift = 5;
            m_oDiveAreaBox.Max.Y += fShift;
            m_oDiveAreaBox.Min.Y -= fShift;

            Vector3 oCenter = Vector3.One;

            if (oRight)
                oCenter.X = m_oDiveAreaBox.Max.X;
            else
                oCenter.X = m_oDiveAreaBox.Min.X;
            oCenter.Y = (m_oDiveAreaBox.Max.Y + m_oDiveAreaBox.Min.Y) * 0.5f;
            oCenter.Z = m_oDiveAreaBox.Min.Z;
            var oRadius = Vector3.Distance(m_oDiveAreaBox.Min, m_oDiveAreaBox.Max) * 0.4f;

            m_oDiveAreaSphere = new BoundingSphere(oCenter, oRadius);
            m_oMaxGoalieArea = m_oDiveAreaSphere;
            m_oMaxGoalieArea.Radius = m_oGoalBounds.Max.Y - m_oGoalBounds.Min.Y;
            m_oMaxGoalieArea.Radius *= 0.35f;
            if (oRight)
                fShift = -3;
            else
                fShift = 3;
            m_oMaxGoalieArea.Center.X += fShift;
            m_oGoalieArea = new BoundingSphere(m_oMaxGoalieArea.Center, Radius * 1.5f);

            if (oRight)
                _LastDirection = -Vector3.UnitX;
            else
                _LastDirection = Vector3.UnitX;

            m_oDiveAreaBox.Max.Z *= 0.5f;
            m_oHopAreaBox = m_oDiveAreaBox;
            m_oHopAreaBox.Max.Z += (m_oDiveAreaBox.Max.Z - m_oDiveAreaBox.Min.Z) * 3;
        }

        public override void Input(MatchScreen3D oMatchScreen)
        {
            if (ControllingPlayer.IsAI)
            {
                if (oMatchScreen is HockeyGameScreen3D)
                    Input((HockeyGameScreen3D)oMatchScreen);
            }
        }

        private void Input(HockeyGameScreen3D oHockeyGame)
        {
            var oDirection = Vector3.Zero;

            if (Condition.IsNeutral)
            {
                m_oPositionToLookAt = Vector3.Zero;
                var oPuck = oHockeyGame.Puck;
                var oPuckHolder = oHockeyGame.PuckHolder;

                #region Update Goalie Area
                if (oPuckHolder != null)
                {
                    m_oPositionToLookAt = oPuckHolder.Position + oPuckHolder.Velocity * 50;
                    if (oPuck != null)
                    {
                        m_oPositionToLookAt += oPuck.Position;
                        m_oPositionToLookAt *= 0.5f;
                    }
                    UpdateGoalieArea(m_oPositionToLookAt, oPuckHolder);
                }

                else if (oPuck != null)
                {
                    m_oPositionToLookAt = oPuck.Position;
                    UpdateGoalieArea(m_oPositionToLookAt, oPuck);
                }
                #endregion

                if (m_oPositionToLookAt == Vector3.Zero)
                    m_oPositionToLookAt = Vector3.UnitX;

                if (m_oGoalieArea.Contains(Position) != ContainmentType.Contains)
                {
                    oDirection = m_oGoalieArea.Center - Position;
                    if (oDirection != Vector3.Zero)
                    {
                        oDirection.Normalize();
                    }
                }

                #region Focus On Puck Handler
                if (oPuckHolder != null)
                {
                    if (oPuckHolder.CollidesWith(m_oDiveAreaSphere))
                    {
                        if (oPuckHolder.Condition.IsNeutral && Condition.IsNeutral)
                        {
                            oDirection = oPuckHolder.Position - Position;
                            if (oDirection != Vector3.Zero)
                                oDirection.Normalize();

                            Direction = oDirection;
                            Tackle();
                        }
                    }
                }
                #endregion

                #region Focus on Puck
                else if (oPuck != null)
                {
                    var oPuckDirection = (oPuck.Position + oPuck.Velocity) - oPuck.Position;
                    Ray? oRay = null;
                    if (oPuckDirection != Vector3.Zero)
                    {
                        oPuckDirection.Normalize();
                        oRay = new Ray(oPuck.Position, oPuckDirection);
                    }

                    if (oPuck.CollidesWith(m_oDiveAreaSphere))
                    {
                        if (TeamSide == Alliance.Home && (oPuck.VelocityX > 0))
                        {
                            return;
                        }

                        if (TeamSide == Alliance.Away && (oPuck.VelocityX < 0))
                        {
                            return;
                        }

                        var oDive = oPuck.CollidesWith(m_oDiveAreaBox);
                        var oHop = oPuck.CollidesWith(m_oHopAreaBox);
                        if (oDive || oHop)
                        {
                            if (oDive)
                            {
                                if (oPuck.Position.Y < Position.Y)
                                {
                                    oDirection = -3 * Vector3.UnitY;
                                }
                                else
                                {
                                    oDirection = 3 * Vector3.UnitY;
                                }
                                if (oPuck.Position.X < Position.X)
                                {
                                    oDirection.X = -1;
                                }
                                else
                                {
                                    oDirection.X = 1;
                                }

                                if (oDirection != Vector3.Zero)
                                {
                                    oDirection.Normalize();
                                }

                                Direction = oDirection;

                                BoundingSphere oCombinedSphere = BoundingSphere.CreateMerged(PuckCollisionTop, PuckCollisionBottom);
                                //oCombinedSphere.Radius += 0.15f;
                                oCombinedSphere.Center.Z += 0.5f;

                                if (oRay != null)
                                {
                                    if (oRay.Value.Intersects(oCombinedSphere) == null)
                                    {
                                        Dive();
                                    }
                                }
                            }
                            else if (oHop)
                            {
                                if (Position.Z == 0)
                                    Hop();
                            }
                            return;
                        }
                    }
                    else
                    {
                        //if (oRay != null)
                        //{
                        //    var oDistance = oRay.Value.Intersects(m_oDiveAreaSphere);
                        //    if (oDistance != null)
                        //    {
                        //        m_oGoalieArea.Center = oRay.Value.Position + oRay.Value.Direction * oDistance.Value;
                        //    }
                        //}
                    }
                }

                if (oDirection != Vector3.Zero)
                    oDirection.Normalize();

                #endregion
            }

            if (float.IsNaN(oDirection.X) || float.IsNaN(oDirection.Y) || float.IsNaN(oDirection.Z))
            {
                oDirection = Vector3.Zero;
            }

            Direction = oDirection;

        }

        private void UpdateGoalieArea(Vector3 oFocus, Person3D oPerson)
        {
            var oDirection = Vector3.Zero;

            var oLeft = m_oDiveAreaBox.Max - oFocus;
            var oRight = m_oDiveAreaBox.Max;
            oRight.Y = m_oDiveAreaBox.Min.Y;
            oRight -= oFocus;
            oRight.Z = 0;
            oLeft.Z = 0;

            var oLeftLength = (oLeft).X;
            var oRightLength = (oRight).X;
            var oLength = ((oLeftLength + oRightLength) * 0.5f) * 0.9f;

            if (oLeft == Vector3.Zero || oRight == Vector3.Zero)
                return;

            oLeft.Normalize();
            oRight.Normalize();
            oDirection = oLeft + oRight;
            if (oDirection == Vector3.Zero)
                return;

            oDirection.Normalize();
            m_oGoalieArea.Center = (oFocus * new Vector3(1, 1, 0)) + (oDirection * oLength);

            if (m_oMaxGoalieArea.Contains(m_oGoalieArea.Center) != ContainmentType.Contains)
            {
                oDirection = m_oGoalieArea.Center - m_oMaxGoalieArea.Center;
                if (oDirection == Vector3.Zero)
                    return;

                oDirection.Normalize();
                m_oGoalieArea.Center = m_oMaxGoalieArea.Center + oDirection * m_oMaxGoalieArea.Radius;
            }
        }

        private void UpdateGoalieArea(Vector3 oFocus, Puck3D oPuck)
        {
            var oDirection = Vector3.Zero;

            var oPuckDirection = (oPuck.Position + oPuck.Velocity) - oPuck.Position;
            if (oPuckDirection != Vector3.Zero)
            {
                oPuckDirection.Z = 0;
                oPuckDirection.Normalize();

                Ray oRay = new Ray(oPuck.Position * new Vector3(1, 1, 0), oPuckDirection);

                var oDistance = oRay.Intersects(m_oGoalBounds);
                if (oDistance != null)
                {
                    m_oGoalieArea.Center = oRay.Position + oRay.Direction * oDistance.Value * 0.95f;
                }
                else
                {
                    oDirection = oPuck.Position - Position;
                    if (oDirection != Vector3.Zero)
                    {
                        oDirection.Normalize();
                    }

                    m_oGoalieArea.Center = m_oGoalieArea.Center + oDirection * m_oMaxGoalieArea.Radius * 0.5f;
                }
            }

            if (m_oMaxGoalieArea.Contains(m_oGoalieArea.Center) != ContainmentType.Contains)
            {
                oDirection = m_oGoalieArea.Center - m_oMaxGoalieArea.Center;
                if (oDirection == Vector3.Zero)
                    return;

                oDirection.Normalize();
                m_oGoalieArea.Center = m_oMaxGoalieArea.Center + oDirection * m_oMaxGoalieArea.Radius;
            }
        }


        public override void InputClient(Blockey.GameObjects3D.Camera3D oCamera)
        {
            // Do Nothing
        }

        protected override void UpdateBoundingSpheres()
        {
            base.UpdateBoundingSpheres();

            m_oPuckCollisionSphereBottom = BaseSphere;
            m_oPuckCollisionSphereBottom.Radius *= 1.5f;

            var oUp = Vector3.Transform(Vector3.UnitY * Radius * 0.5f, _BodyDrawable.World) - Position;
            m_oPuckCollisionSphereTop = m_oPuckCollisionSphereBottom;
            m_oPuckCollisionSphereTop.Center += oUp;

            //BoundingSphere oCombinedSphere = BoundingSphere.CreateMerged(PuckCollisionTop, PuckCollisionBottom);
            ////oCombinedSphere.Radius += 0.15f;
            //oCombinedSphere.Center.Z += 0.5f;
            //DebugShapeRenderer.AddBoundingSphere(oCombinedSphere, Color.Green);
        }

        public override void UpdateRotation(bool bIsClient, bool bRotateImmediately)
        {
            if (bIsClient == false)
            {
                var oDirection = Position - m_oPositionToLookAt;
                if (oDirection == Vector3.Zero)
                    oDirection = Vector3.UnitY;

                if (Condition.Name == ConditionName.Diving)
                {
                    if (TeamSide == Alliance.Home)
                    {
                        oDirection = -Vector3.UnitX;
                    }
                    else
                    {
                        oDirection = Vector3.UnitX;
                    }
                }

                oDirection.Normalize();

                _Rotation.Z = All.VectorToAngle(new Vector2(oDirection.X, oDirection.Y)) + MathHelper.PiOver2;
            }

            base.UpdateRotation(bIsClient, bRotateImmediately);
        }

        public override void Draw(GraphicsDevice oGraphics, Camera3D oCamera)
        {
            base.Draw(oGraphics, oCamera);

            if (DebugShapeRenderer.ShowLines)
            {
                DebugShapeRenderer.AddBoundingSphere(m_oPuckCollisionSphereTop, Color.Green);
                DebugShapeRenderer.AddBoundingSphere(m_oPuckCollisionSphereBottom, Color.Green);

                DebugShapeRenderer.AddBoundingBox(m_oDiveAreaBox, Color.Blue);
                DebugShapeRenderer.AddBoundingBox(m_oHopAreaBox, Color.Blue);
                DebugShapeRenderer.AddBoundingSphere(m_oDiveAreaSphere, Color.Blue);

                DebugShapeRenderer.AddBoundingSphere(m_oGoalieArea, Color.Red);
                DebugShapeRenderer.AddBoundingSphere(m_oMaxGoalieArea, Color.Red);
            }
        }

        public BoundingSphere PuckCollisionTop
        {
            get { return m_oPuckCollisionSphereTop; }
        }
        public BoundingSphere PuckCollisionBottom
        {
            get { return m_oPuckCollisionSphereBottom; }
        }

        private BoundingBox m_oGoalBounds;
        private BoundingSphere m_oGoalieArea;
        private BoundingSphere m_oMaxGoalieArea;
        private BoundingBox m_oDiveAreaBox;
        private BoundingBox m_oHopAreaBox;
        private BoundingSphere m_oDiveAreaSphere;
        private Vector3 m_oPositionToLookAt;
        private BoundingSphere m_oPuckCollisionSphereBottom;
        private BoundingSphere m_oPuckCollisionSphereTop;

    }
}
